/*
 * Searcher.java
 *
 * Created on May 7, 2007, 11:24 PM
 *
 *  Life Logger v11.0
    Copyright (C) 2007  Anand Kishore (anand@semanticvoid.com)
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

package com.semanticvoid.lifelogger.karma.search.factory.decorator;

import com.semanticvoid.lifelogger.db.ConnectionMgr;
import com.semanticvoid.lifelogger.entity.BrowseHistoryEntity;
import com.semanticvoid.lifelogger.entity.SearchHistoryEntity;
import com.semanticvoid.lifelogger.karma.search.interfaces.ISearch;
import com.semanticvoid.lifelogger.karma.search.query.QueryGenerator;
import com.semanticvoid.lifelogger.utils.DateHelper;
import java.sql.ResultSet;
import java.util.Calendar;
import java.util.Collections;
import java.util.List;
import java.util.Vector;

/**
 *
 * @author anand kishore
 */
public class Searcher implements ISearch {
    
    ConnectionMgr db = null;
    
    public Searcher() {
        try {
            db = new ConnectionMgr();
        } catch(Exception e) {
            e.printStackTrace();
            System.exit(1);
        }
    }
    
    public Vector<BrowseHistoryEntity> searchBrowseHistory(String query, short browseType, String fromDate, String toDate) {
        Vector<BrowseHistoryEntity> results = new Vector<BrowseHistoryEntity>();
        
        if(query == null && (fromDate.equals("") || toDate.equals(""))) {
            return results; 
        }
        
        String dbQuery = QueryGenerator.generateSearchQueryForBrowseHistory(query, browseType, fromDate, toDate);
        
        System.out.println(dbQuery);
        
        ResultSet rs = db.fire(dbQuery);
        
        if(rs != null) {
            try {
                while(rs.next()) {
                    String guid = rs.getString("guid");
                    
                    String title = rs.getString("title");
                    
                    String link = rs.getString("link");
                    
                    String dateString = rs.getString("pubDate");
                    Calendar bDate = DateHelper.convertMySQLDateStringToCalendar(dateString);
                    
                    short type = rs.getShort("type");
                    String searchContext = rs.getString("searchContext");
                    float score = rs.getFloat("score");
                    String excerpts = extractExcerpts(query.split(" "), rs.getString("content"), 3, 50, "..");
                    
                    BrowseHistoryEntity bEntity = new BrowseHistoryEntity(guid, link, bDate, title, type, searchContext, null, excerpts);
                    bEntity.setScore(score);
                    
                    results.add(bEntity);
                }
            } catch(Exception e) {
                e.printStackTrace();
            }
        }
        
        return results;
    }
    
    public Vector<BrowseHistoryEntity> searchBrowseHistory(String query, short browseType) {
        return searchBrowseHistory(query, browseType, null, null);
    }
    
    public Vector<SearchHistoryEntity> searchSearchHistory(String query, String fromDate, String toDate) {
        Vector<SearchHistoryEntity> results = new Vector<SearchHistoryEntity>();
        
        if(query == null && (fromDate.equals("") || toDate.equals(""))) {
            return results; 
        }
        
        String dbQuery = QueryGenerator.generateSearchQueryForSearchHistory(query, fromDate, toDate);
        
        System.out.println(dbQuery);
        
        ResultSet rs = db.fire(dbQuery);
        
        if(rs != null) {
            try {
                while(rs.next()) {
                    String guid = rs.getString("guid");
                    String link = rs.getString("link");
                    
                    String dateString = rs.getString("pubDate");
                    Calendar sDate = DateHelper.convertMySQLDateStringToCalendar(dateString);
                    
                    String keywords = rs.getString("keywords");
                    float score = rs.getFloat("score");
                    // Not setting content
                    
                    SearchHistoryEntity sEntity = new SearchHistoryEntity(guid, link, sDate, keywords);
                    sEntity.setScore(score);
                    
                    results.add(sEntity);
                }
            } catch(Exception e) {
                e.printStackTrace();
            }
        }
        
        return results;
    }
    
    public Vector<SearchHistoryEntity> searchSearchHistory(String query) {
        return searchSearchHistory(query, null, null);
    }

    private String extractExcerpts(String[] queryTerms, String content, int num, int paddingLength, String paddingText) {
        int index = 0;
        int termIndex = -1;
        int startIndex = -1;
        int endIndex = -1;
        int count = 0;
        int numOfExcerpts = -1;
        int quit = 0;
        String lowerCaseContent = content.toLowerCase();
        
        // StringBuffer to hold the excerpts
        StringBuffer excerpts = new StringBuffer();
        
        // List of the excerpts
        Vector<Excerpt> list = new Vector<Excerpt>();
        
        // If the query term is NULL then we need to display the first few lines
        // of the document without highlighting. This is to give a hint as to what the
        // document is all about during BROWSE.
        if(queryTerms.length == 1 && queryTerms[0].equalsIgnoreCase("null")) {
            //excerpts.append(content.substring(0, 100));
        } else {
            while(true) {
                quit = 0;
                for(String term : queryTerms) {
                    // Added padding so that substrings do not match
                    termIndex = lowerCaseContent.indexOf(" " + term + " ", index);

                    if(termIndex == -1) {
                        quit++;
                        continue;
                    }

                    // Check to see if the start or end exceeds the content limits
                    startIndex = termIndex - paddingLength;
                    if(startIndex < 0) {
                        startIndex = 0;
                    }

                    endIndex = termIndex + term.length() + paddingLength;
                    if(endIndex > lowerCaseContent.length()-1) {
                        endIndex = lowerCaseContent.length()-1;
                    }

                    StringBuffer excerpt = new StringBuffer(content.substring(startIndex, endIndex+1));

                    // Emphasize all the macthing terms in this excerpt
                    int keywordMatchedCount = 0;
                    for(String emphasizeTerm : queryTerms) {
                        // Added padding so that substrings dont match
                        emphasizeTerm = " " + emphasizeTerm + " ";

                        int tempIndex = excerpt.toString().toLowerCase().indexOf(emphasizeTerm);

                        while(tempIndex != -1) {
                            keywordMatchedCount++;
                            excerpt.insert(tempIndex+1, "<b>");
                            excerpt.insert(tempIndex+emphasizeTerm.length()+2, "</b>");

                            tempIndex = excerpt.toString().toLowerCase().indexOf(emphasizeTerm, tempIndex+emphasizeTerm.length()+2);
                        }
                    }

                    // Add the padding text
                    excerpt.insert(0, paddingText);
                    excerpt.insert(excerpt.length(), paddingText);

                    // Add excerpt to list of excerpts
                    //excerpts.append(excerpt.toString());

                    // Create excerpt object
                    Excerpt excerptObj = new Excerpt(excerpt.toString(), keywordMatchedCount, ++numOfExcerpts);
                    // Add it to the list
                    list.add(excerptObj);

                    // Update the index
                    index = endIndex;
                }

                // Break out of the loop if none of the terms match
                if(quit >= queryTerms.length) {
                    break;
                }
            }

            // Do the damn sorting [fingers crossed x)]
            Collections.sort((List) list);

            for(int i=0; i<list.size(); i++) {
                if(i == num) {
                    break;
                }

                Excerpt e = list.get(i);
                excerpts.append(e.getText());
            }
        }
        
        return excerpts.toString();
    }
    
    // Inner class for Excerpt Object
    private class Excerpt implements Comparable<Excerpt> {
        private String text;
        private int keywordCount;
        private int position;
        
        public Excerpt() {
        }
        
        public Excerpt(String txt, int keywordCnt, int pos) {
            text = txt;
            keywordCount = keywordCnt;
            position = pos;
        }
        
        public String getText() {
            return text;
        }
        
        public void setText(String text) {
            this.text = text;
        }
        
        public int getKeywordCount() {
            return keywordCount;
        }
        
        public void setKeywordCount(int keywordCount) {
            this.keywordCount = keywordCount;
        }
        
        public int getPosition() {
            return position;
        }
        
        public void setPosition(int position) {
            this.position = position;
        }
        
        public int compareTo(Excerpt e) {
            if(this.getKeywordCount() > e.getKeywordCount()) {
                return -1;
            } else if(this.getKeywordCount() < e.getKeywordCount()) {
                if(this.getPosition() > e.getPosition()) {
                    return -1;
                } else if(this.getPosition() < e.getPosition()) {
                    return 1;
                }
            }
            
            return 0;
        }
    }
}
